from flask import Flask, request, jsonify
from flask_httpauth import HTTPBasicAuth
from flask_cors import CORS
import csv, logging, secrets, redis, json, time

app = Flask(__name__)

# 全局用户信息
user_infos = {}

# 全局变量用于记录成功和失败请求的次数
# 全局计数器变量
request_counts = []

# 设置日志级别 打印日志
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')
CORS(app)
auth = HTTPBasicAuth()
redis_cli = redis.Redis(host="81.69.247.242", port=6379, password="ACCC897A54AF9BE4D339E13F900BBAD8")


class User:
    def __init__(self, uid, username, password, home_path):
        """
        初始化用户参数
        :param uid: 用户uid
        :param username: 用户名
        :param password: 用户密码
        :param home_path: 用户目录
        """
        self.uid = uid
        self.username = username
        self.password = password
        self.home_path = home_path

    def to_string(self):
        """
        重写to_string
        :return:
        """
        return {
            "uid": self.uid,
            "username": self.username,
            # JSON序列化提出pwd字段
            # "password": self.password,
            "home_path": self.home_path
        }

    @staticmethod
    def get_user_by_uid(uid):
        """
        根据uid获取当前登录用户
        :param uid:
        :return:
        """
        return user_infos.get(uid, "未找到用户")


def init_user_infos(function):
    """
    配制用户数据
    :param function:
    :return:
    """

    def wrapper(*args, **kwargs):
        function(*args, **kwargs)
        with open("users.csv", encoding="utf-8") as f:
            csv_reader = csv.reader(f)
            header = next(csv_reader)
            for row in csv_reader:
                for index in row:
                    info = index.split(";")
                    user_info = User(info[0], info[1], info[2], info[3])
                    user_infos[info[0]] = user_info

    return wrapper


@init_user_infos
def init_pro_config():
    # 这里只会执行一次
    logging.info("flask开始初始化用户信息....")


# 初始化
init_pro_config()


def compute_request_frequency(funtion):
    """
    统计API访问次数
    原生@app.before_request无法统计调用api执行过程（失败/成功）,自定义实现环绕通知
    :param funtion: api接口实现
    :return:
    """

    def handler(*args, **kwargs):
        try:
            result = funtion(*args, **kwargs)
            # 统计调用API成功次数
            record_request(True)
            return result
        except Exception as e:
            # 统计调用API失败次数
            record_request(False)

    handler.__name__ = funtion.__name__
    return handler


def record_request(is_success):
    global request_counts
    request_counts.append((time.time(), is_success))  # 成功请求
    request_counts = [(ts, success) for ts, success in request_counts if ts >= time.time() - 3600]  # 仅保留最近 1 小时内的记录


# 获取过去指定时间段内的请求状态
def get_request_status(duration):
    global request_counts
    end_time = time.time()
    start_time = end_time - duration
    successful_requests = sum(1 for ts, success in request_counts if start_time <= ts <= end_time and success)
    failed_requests = sum(1 for ts, success in request_counts if start_time <= ts <= end_time and not success)
    return successful_requests, failed_requests


def login_check(funtion):
    """
    登录校验
    :param funtion:
    :return:
    """

    def handler(*args, **kwargs):
        token = get_token()
        if token is None:
            return {"msg": "请先登录"}
        return funtion(*args, **kwargs)

    handler.__name__ = funtion.__name__
    return handler


def get_token():
    """
    获取request头token信息
    :return:
    """
    headers = request.headers
    token = headers.get("token")
    if token is None or token == "":
        return None
    return token


@app.route("/")
@compute_request_frequency
def index():
    """
    测试web服务启动
    :return:
    """
    return "Welcome to the Infrastructure API!"


@app.route("/login", methods=["POST"])
@compute_request_frequency
def login():
    """
    登录接口
    :return:
    """
    username = request.form.get("username")
    password = request.form.get("password")
    for item in user_infos:
        user_info = user_infos[item]
        if user_info.username == username and user_info.password == password:
            # 创建用户token信息
            token = secrets.token_hex(16)
            redis_cli.set(str(token), user_info.uid, 3600)
            return {"token": token, "expired": 3600}
    return {"msg": "用户名或密码错误"}


@app.route("/current_user")
@login_check
@compute_request_frequency
def current_user():
    """
    获取当前登录用户
    :return:
    """
    token = get_token()
    if token is None:
        return {"msg": "用户未登录"}
    user_uid = redis_cli.get(str(token))
    return json.dumps(User.get_user_by_uid(user_uid.decode()), default=User.to_string)


@app.route("/logout")
@login_check
@compute_request_frequency
def logout():
    """
    用户登出
    :return:
    """
    token = get_token()
    if token is not None:
        val = redis_cli.get(token)
        if val is None:
            return {"msg": "用户未登录"}
        redis_cli.delete(token)
    return {"msg": "登出成功"}


@app.route('/api/request_count', methods=['GET'])
@login_check
def get_health_status():
    successful_requests_5m, failed_requests_5m = get_request_status(300)
    successful_requests_1h, failed_requests_1h = get_request_status(3600)
    response = {
        'failed_requests_1h': failed_requests_1h,
        'failed_requests_5mins': failed_requests_5m,
        'successful_requests_1h': successful_requests_1h,
        'successful_requests_5mins': successful_requests_5m
    }
    return jsonify(response)


if __name__ == '__main__':
    # 未使用flask提供登录校验装饰器，自定义实现，逻辑一致
    app.run(host='0.0.0.0', port=443, threaded=True)
